package com.ksyun.campus.metaserver.controller;

import com.ksyun.campus.metaserver.domain.BlockInfo;
import com.ksyun.campus.metaserver.domain.ClusterConfig;
import com.ksyun.campus.metaserver.domain.DataServerInfo;
import com.ksyun.campus.metaserver.domain.MetaServerInfo;
import com.ksyun.campus.metaserver.domain.dto.ApiResponse;
import com.ksyun.campus.metaserver.storage.MetadataStore;
import com.ksyun.campus.metaserver.zk.ZooKeeperService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Cluster information and statistics controller
 */
/**
 * 控制器：提供集群元信息与副本分布统计接口
 *
 * 功能：
 *   1. /info          - 获取当前集群状态（Leader、DataServer 列表、配置等）
 *   2. /replicaStats  - 获取各 DataServer 的副本数量统计
 *
 * 适用场景：
 *   - 管理员查看集群运行状态
 *   - 监控系统采集健康信息
 */
@Slf4j
@RestController
@RequestMapping("/api/v1/cluster")
public class ClusterController {
    
    @Autowired
    private ZooKeeperService zooKeeperService;
    
    @Autowired
    private MetadataStore metadataStore;
    

    
    /**
     * Get cluster information
     */
    /**
     * 获取集群总体信息
     *
     * GET /info
     *
     * 返回：
     * {
     *   "leader": { "id": "...", "host": "...", "port": 9000 },
     *   "followers": [],
     *   "dataServers": [
     *     { "dsId": "dn1", "host": "10.0.0.1", "port": 50010, "capacity": 1073741824, "used": 536870912, "lastSeen": "2025-08-14T11:00:00" },
     *     ...
     *   ],
     *   "config": { "replicationFactor": 3, "blockSize": 524288 }
     * }
     */
    @GetMapping("/info")
    public ApiResponse<Map<String, Object>> getClusterInfo() {
        try {
            MetaServerInfo leaderInfo = zooKeeperService.getLeaderInfo();
            List<DataServerInfo> dataServers = zooKeeperService.getCurrentDataServers();
            ClusterConfig config = metadataStore.getClusterConfig().orElse(ClusterConfig.defaultConfig());
            
            Map<String, Object> clusterInfo = new HashMap<>();
            
            // Leader info
            if (leaderInfo != null) {
                clusterInfo.put("leader", Map.of(
                        "id", leaderInfo.getInstanceId(),
                        "host", leaderInfo.getHost(),
                        "port", leaderInfo.getPort()
                ));
            }
            
            // TODO: Get follower info from ZK
            clusterInfo.put("followers", List.of());
            
            // Data servers
            List<Map<String, Object>> dsInfos = dataServers.stream().map(ds -> {
                Map<String, Object> info = new HashMap<>();
                info.put("dsId", ds.getDsId());
                info.put("host", ds.getHost());
                info.put("port", ds.getPort());
                info.put("capacity", ds.getCapacityBytes());
                info.put("used", ds.getUsedBytes());
                info.put("lastSeen", ds.getLastSeen() != null ? ds.getLastSeen().toString() : "unknown");
                return info;
            }).collect(Collectors.toList());
            
            clusterInfo.put("dataServers", dsInfos);
            
            // Config
            clusterInfo.put("config", Map.of(
                    "replicationFactor", config.getReplicationFactor(),
                    "blockSize", config.getBlockSizeBytes()
            ));
            
            return ApiResponse.success(clusterInfo);
        } catch (Exception e) {
            log.error("Error getting cluster info", e);
            return ApiResponse.error(e.getMessage());
        }
    }
    /**
     * 获取副本分布统计信息
     *
     * GET /replicaStats
     *
     * 返回：
     * {
     *   "byDataServer": [
     *     { "dsId": "dn1", "primaryBlocks": 100, "replicaBlocks": 200, "total": 300 },
     *     ...
     *   ],
     *   "ts": "2025-08-14T11:05:00"
     * }
     */
    /**
     * Get replica distribution statistics
     */
    @GetMapping("/replicaStats")
    public ApiResponse<Map<String, Object>> getReplicaStats() {
        try {
            List<BlockInfo> allBlocks = metadataStore.getAllBlocks();
            List<DataServerInfo> dataServers = zooKeeperService.getCurrentDataServers();
            
            // Count blocks by data server
            Map<String, Integer> primaryBlocks = new HashMap<>();
            Map<String, Integer> replicaBlocks = new HashMap<>();
            
            // Initialize counters
            for (DataServerInfo ds : dataServers) {
                primaryBlocks.put(ds.getDsId(), 0);
                replicaBlocks.put(ds.getDsId(), 0);
            }
            
            // Count blocks
            for (BlockInfo block : allBlocks) {
                for (BlockInfo.ReplicaInfo replica : block.getReplicas()) {
                    String dsId = replica.getDsId();
                    if (replica.getRole() == BlockInfo.ReplicaInfo.ReplicaRole.PRIMARY) {
                        primaryBlocks.put(dsId, primaryBlocks.getOrDefault(dsId, 0) + 1);
                    } else {
                        replicaBlocks.put(dsId, replicaBlocks.getOrDefault(dsId, 0) + 1);
                    }
                }
            }
            
            // Build response
            List<Map<String, Object>> byDataServer = dataServers.stream().map(ds -> {
                String dsId = ds.getDsId();
                int primary = primaryBlocks.getOrDefault(dsId, 0);
                int replica = replicaBlocks.getOrDefault(dsId, 0);
                
                Map<String, Object> stats = new HashMap<>();
                stats.put("dsId", dsId);
                stats.put("primaryBlocks", primary);
                stats.put("replicaBlocks", replica);
                stats.put("total", primary + replica);
                return stats;
            }).collect(Collectors.toList());
            
            return ApiResponse.success(Map.of(
                    "byDataServer", byDataServer,
                    "ts", LocalDateTime.now().toString()
            ));
        } catch (Exception e) {
            log.error("Error getting replica stats", e);
            return ApiResponse.error(e.getMessage());
        }
    }
}
